#coding:utf-8


from twisted.internet import reactor
import base
import datamethod as dm
from report import RecordInfo, RecordConnection
import time
from buss import market as bussmarket
import report
import sys,os
import dttime

class TestFlowList:
    def __init__(self, testList=[]):
        self.testList = []
        for testFlow in testList:
            self.testList += testFlow.getTestList()
        self.currentTestCase = None
        self._repeat = -1
        
    def appendTest(self, testList):
        self.testList.append(testList)
        
    def nextTestCase(self):
        try:
            self.currentTestCase = self.testList.pop(0)
            self._repeat = self.currentTestCase.getRepeat()
            return True
        except IndexError:
            return False
        
    def nextData(self):
        if self._repeat <= 0:
            return None, None
        self._repeat -= 1
        return self.getCurrentData()
        
    def getCurrentPatience(self):
        if self.currentTestCase:
            return self.currentTestCase.getPatience()
    
    def getCurrentRest(self):
        if self.currentTestCase:
            return self.currentTestCase.getRest()
    
    def getCurrentRepeat(self):
        if self.currentTestCase:
            return self.currentTestCase.getRepeat()
    
    def getCurrentData(self):
        if self.currentTestCase:
            return self.currentTestCase.getBussType(), \
                    self.currentTestCase.getBussData()
                
    def getTestTime(self):
        cnt = 0
        for test in self.testList:
            cnt = cnt + test.getUseTime()
        if self.currentTestCase:
            t = self.currentTestCase.getPaitence() + self.currentTestCase.getRest()
            cnt = cnt + t * self._repeat
        return cnt
        

class BaseVehicle(object):
    """Base vehicle class. You could not use it."""
    index = 0
    def __init__(self, tel):
        self.index = self.index + 1
        self.tel = tel
        telu = dm.asc2data(tel) # 下发指令使用的手机号序列
        assert len(telu) <= 15, "Length of tel can't be more than 15."
        self.telu = telu + (15 - len(telu))*[0x20]
        
    def getTel(self):
        return self.tel
        
class VehicleData(BaseVehicle):
    def __init__(self, factory, tel):
        BaseVehicle.__init__(self, tel)
        self.factory = factory
        self._started = False
        self._connected = False
        self.currentHunter = None
        self.testList = None
        self.currentInfo = None
        self.reportPath= ""
        
    def __del__(self):
        pass
    
    def setTestList(self, testFlowList):
        self.testList = TestFlowList(testFlowList)
        
    def appendTestCase(self, testcase):
        if not self.testList:
            self.testList = TestFlowList()
        self.testList.appendTest(testcase)
        
    def setReportPath(self, path):
        self.reportPath = path + "/" + self.tel
        try:
            os.mkdir(self.reportPath)
        except:
            pass
        
    def createSubPath(self, path):
        p = self.reportPath + "/" + path
        try:
            os.mkdir(p)
        except:
            pass
        return p
        
    def getTestTime(self):
        if self.testList:
            self.testList.getTestTime()
        return 0
    
    def work(self):
        busstype, bussdata = self.testList.nextData()
        if not busstype:
            self.nextTestCase()
        else:
            hunter = bussmarket.hireHunter(busstype)
            if hunter:
                self.currentHunter = hunter(self)
                self.currentHunter.startWork(busstype, bussdata)
                self.startDelay(self.testList.getCurrentPatience(), self.playTest)
        
    def notifyWorkCompleted(self, hunter):
        if hunter == self.currentHunter:
            self.currentHunter = None
        self.startDelay(self.testList.getCurrentRest(), self.playTest)
    
    def nextTestCase(self):
        if self.testList.nextTestCase():
            self.recordNewTestCase()
            return self.playTest()
        else:
            self.closeTest()
            
    def recordNewTestCase(self):
        if not self.currentInfo:
            report.error(u"%s试图向不存在的数据库记录数据"%self.tel)
        busstype, bussdata = self.testList.getCurrentData()
        self.currentInfo.recordNewTestCase(busstype = dm.data2str(busstype), 
                                       bussdata = dm.data2str(bussdata),
                                       repeat = self.testList.getCurrentRepeat(),
                                       patience = self.testList.getCurrentPatience(),
                                       rest = self.testList.getCurrentRest())
            
    def startDelay(self, *args, **kw):
        self.cancelDelay()
        self._nextCalled = reactor.callLater(*args, **kw)
            
    def cancelDelay(self):
        try:
            self._nextCalled.cancel()
        except:
            pass
        
    def playTest(self):
        """ play test. Call it after vehicle logon or close one test.
        One buss instance is return from test list and pass to relative 
        hunter class.If buss instance is None, then test is completed.
        """
        if self._started and self._connected:
            self.reportUser('sendTestStart', self.tel) 
            #self.factory.user.sendTestProcess(self.tel, value, self.totalTime)
            self.work()
                
    def startTest(self):
        self._started = True
        conn = RecordConnection(self.reportPath + "/data")
        self.currentInfo = RecordInfo(conn)
        self.currentInfo.initTable(self.tel)
        self.currentInfo.recordTestStarted()
        self.reportMessage(u"测试开始")
        return self.playTest()

    def closeTest(self):
        if self.currentInfo:
            self.currentInfo.recordTestClosed()
        self.currentInfo = None
        self._started = False
        self.reportUser('sendTestStop', self.tel)
        self.reportMessage(u"测试完成")
            
    def reportUser(self, callablestring, *args, **kw):
        if hasattr(self.factory, 'user'):
            eval("self.factory.user.%s"%callablestring)(*args, **kw)
            
    def reportMessage(self, msg):
        self.reportUser('sendMessage', self.tel, msg)
        
    def _reportUserData(self, data):
        data = dm.data2str(data)
        self.reportUser('sendData', self.tel, data)
        
    def sendData(self, busstype, bussdata, response = False):
        connector = self.factory.getConnector(self.tel)
        if not connector: return
        self._reportUserData(busstype+bussdata)  # ....
        data = busstype + self.telu + base.SERVER_TELNUMBER + bussdata
        data = base.SERVER_AREACODE + base.SERVER_VERSION + data
        data.append(dm.getchecksum_buss(data))
        if response:
            data = [0x10, 0x82] + data
        else:
            data = [0x10, 0x83] + data
        connector.sendData(data)
        
    def feedData(self, data):
        self._reportUserData(data) # ....
        busstype, bussdata = data[:2], data[2:]
        if self.currentHunter:
            if not self.currentHunter.recvData(busstype, bussdata):
                """ 该hunter不需要此类型 """
        #else:report.error("this data may be not needed.%s"%dm.data2str(data))

    def connectionCreated(self):
        # 有问题
        self._connected = True
        if not self.currentHunter:
            reactor.callLater(2, self.playTest)
        self.reportMessage(u"车辆上线.")
        self.reportUser('sendLoginState', self.tel, True)
            
    def connectionLost(self):
        # 有问题
        self._connected = False
        if self.currentHunter:
            self.cancelDelay()
        self.reportMessage(u"车辆掉线.")
        self.reportUser('sendLoginState', self.tel, False)
        self.reportUser('sendTestPause', self.tel)
        
    def isOnline(self):
        """ 
        If vehicle is logon, return True, else return
        False.
        """
        return self._connected
        
    def isStartingTest(self):
        """ 
        If test is started, return True, else return
        False.
        """
        return self._started
        
        
